package javablackbelt.beans.factory.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.util.StringValueResolver;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

public class Base64PropertyDecoderBeanFactoryPostProcessor extends Base64PropertyDecoderSupport 
			implements BeanNameAware, BeanFactoryAware, BeanFactoryPostProcessor, PriorityOrdered {

	private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered
	private String beanName;
	private BeanFactory beanFactory;

	public void setOrder(int order) {
		this.order = order;
	}

	public int getOrder() {
		return this.order;
	}

	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactoryToProcess) throws BeansException {

		BeanDefinitionEncodedPropertyVisitor visitor = 
			new BeanDefinitionEncodedPropertyVisitor(this, new Base64DecodingStringValueResolver());

		String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
		for (int i = 0; i < beanNames.length; i++) {
			// Check that we're not parsing our own bean definition,
			// to avoid failing on unresolvable placeholders in properties file
			// locations.
			if (!(beanNames[i].equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
				BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(beanNames[i]);
				try {
					visitor.visitBeanDefinition(bd);
				} catch (BeanDefinitionStoreException ex) {
					throw new BeanDefinitionStoreException(bd
							.getResourceDescription(), beanNames[i], ex
							.getMessage());
				}
			}
		}
	}
	
	/**
	 * BeanDefinitionVisitor that resolves Base64 encoded String.
	 */
	private class Base64DecodingStringValueResolver implements StringValueResolver {

		public String resolveStringValue(String encodedProp) throws BeansException {
			return encodedProp != null ? new String(Base64.decode(encodedProp)) : "";
		}
	}

	public void setBeanName(String beanName) {
		this.beanName = beanName;
	}

	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}

}
